/**
 * NSGAIIMNO_main.java
 *
 * @author Juan J. Durillo
 * @author Antonio J. Nebro
 * @version 1.0
 *   This implementation of NSGA-II makes use of a QualityIndicatorMNO object
 *   to obtained the convergence speed of the algorithm. This version is used
 *   in the paper:
 *     A.J. Nebro, J.J. Durillo, C.A. Coello Coello, F. Luna, E. Alba 
 *     "A Study of Convergence Speed in Multi-Objective Metaheuristics." 
 *     To be presented in: PPSN'08. Dortmund. September 2008.
 *     
 *   Besides the classic NSGA-II, a steady-state version (ssNSGAII) is also
 *   included (See: J.J. Durillo, A.J. Nebro, F. Luna and E. Alba 
 *                  "On the Effect of the Steady-State Selection Scheme in 
 *                  Multi-Objective Genetic Algorithms"
 *                  5th International Conference, EMO 2009, pp: 183-197. 
 *                  April 2009)
 *   
 */
package ufpr.mestrado.ais.metaheuristics.nsga2mno;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;

import jmetal.base.Algorithm;
import jmetal.base.Operator;
import jmetal.base.Problem;
import jmetal.base.SolutionSet;
import jmetal.base.operator.mutation.MutationFactory;
import jmetal.qualityIndicator.QualityIndicator;
import jmetal.util.Configuration;
import jmetal.util.JMException;
import ufpr.mestrado.ais.base.operator.bw.MR;
import ufpr.mestrado.ais.base.operator.crossover.SBXCrossoverMNO;
import ufpr.mestrado.ais.base.operator.crossover.SinglePointCrossoverMNO;
import ufpr.mestrado.ais.base.operator.mutation.BitFlipMutationMNO;
import ufpr.mestrado.ais.base.operator.selection.BinaryTournament2MNO;
import ufpr.mestrado.ais.problems.mno.DTLZ.DTLZMNO2;
import ufpr.mestrado.ais.util.DominanceComparatorMNO;

public class NSGAIIMNO_main {
	public static Logger logger_; // Logger object
	public static FileHandler fileHandler_; // FileHandler object

	/**
	 * @param args
	 *            Command line arguments.
	 * @throws JMException
	 * @throws IOException
	 * @throws SecurityException
	 *             Usage: three options -
	 *             jmetal.metaheuristics.nsgaII.NSGAII_main -
	 *             jmetal.metaheuristics.nsgaII.NSGAII_main problemName -
	 *             jmetal.metaheuristics.nsgaII.NSGAII_main problemName
	 *             paretoFrontFile
	 */
	public static void main(String[] args) throws JMException,
			SecurityException, IOException, ClassNotFoundException {
		Problem problem; // The problem to solve
		Algorithm algorithm; // The algorithm to use
		Operator crossover; // Crossover operator
		Operator mutation; // Mutation operator
		Operator selection; // Selection operator

		QualityIndicator indicators; // Object to get quality indicators

		// Logger object and file to store log messages
		logger_ = Configuration.logger_;
		fileHandler_ = new FileHandler("NSGAIIMNO_main.log");
		logger_.addHandler(fileHandler_);

		indicators = null;

		//problem = new DTLZMNO2("Real", 14, 5, 0.5);
		problem = new DTLZMNO2("BinaryReal", 14, 5, 0.5);

		indicators = new QualityIndicator(problem, args[0]);

		algorithm = new NSGAIIMNO(problem);
		// algorithm = new ssNSGAII(problem);

		// Algorithm parameters
		algorithm.setInputParameter("populationSize", 200);
		algorithm.setInputParameter("maxEvaluations", 300);

		// Mutation and Crossover for Real codification
		/*
		crossover = new SBXCrossoverMNO();
		crossover.setParameter("probability", 0.9);
		crossover.setParameter("distributionIndex", 20.0);

		mutation = MutationFactory.getMutationOperator("PolynomialMutation");
		mutation.setParameter("probability",
				1.0 / problem.getNumberOfVariables());
		mutation.setParameter("distributionIndex", 20.0);
		*/
		
		crossover = new SinglePointCrossoverMNO();
		crossover.setParameter("probability", 0.9);

		mutation = new BitFlipMutationMNO();
		mutation.setParameter("probability", 1.0 / problem.getNumberOfVariables());
		
		// Selection Operator
		selection = new BinaryTournament2MNO(new DominanceComparatorMNO());

		// Add the operators to the algorithm
		algorithm.addOperator("crossover", crossover);
		algorithm.addOperator("mutation", mutation);
		algorithm.addOperator("selection", selection);

		// bw_operator operador
		//algorithm.addOperator("bw_operator", new MR());

		// Add the indicator object to the algorithm
		algorithm.setInputParameter("indicators", indicators);

		// Execute the Algorithm
		long initTime = System.currentTimeMillis();
		SolutionSet population = algorithm.execute();
		long estimatedTime = System.currentTimeMillis() - initTime;

		// Result messages
		logger_.info("Total execution time: " + estimatedTime + "ms");
		logger_.info("Variables values have been writen to file VAR");
		population.printVariablesToFile("result/VAR.var");
		logger_.info("Objectives values have been writen to file FUN");
		population.printObjectivesToFile("result/FUN.fun");

		if (indicators != null) {
			logger_.info("Quality indicators");
			logger_.info("Hypervolume: "
					+ indicators.getHypervolume(population));
			logger_.info("GD         : " + indicators.getGD(population));
			logger_.info("IGD        : " + indicators.getIGD(population));
			logger_.info("Spread     : " + indicators.getSpread(population));
			logger_.info("Epsilon    : " + indicators.getEpsilon(population));

			int evaluations = ((Integer) algorithm
					.getOutputParameter("evaluations")).intValue();
			logger_.info("Speed      : " + evaluations + " evaluations");
		} // if
	} // main
} // NSGAIIMNO_main
